home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Camelot / Camelot 078 (1990-06)(Swedish User Group of Amiga)(SE)(PD)[WB].zip / Camelot 078 (1990-06)(Swedish User Group of Amiga)(SE)(PD)[WB].adf / MSH / src / devio.c < prev    next >
C/C++ Source or Header  |  1990-06-17  |  48KB  |  1,903 lines

  1. /*-
  2.  * $Id: devio.c,v 1.30 90/06/04 23:18:52 Rhialto Rel $
  3.  * $Log:    devio.c,v $
  4.  * Revision 1.30  90/06/04  23:18:52  Rhialto
  5.  * Release 1 Patch 3
  6.  * 
  7.  * DEVIO.C
  8.  *
  9.  * The messydisk.device code that does the real work.
  10.  *
  11.  * This code is (C) Copyright 1989 by Olaf Seibert. All rights reserved. May
  12.  * not be used or copied without a licence.
  13. -*/
  14.  
  15. #include "dev.h"
  16. #include "device.h"
  17.  
  18. /*#undef DEBUG            /**/
  19. #ifdef DEBUG
  20. #   define    debug(x)  dbprintf x
  21. #else
  22. #   define    debug(x)
  23. #endif
  24.  
  25. struct DiskResource *DRResource;/* Argh! A global variable! */
  26. void *CiaBResource;        /* And yet another! */
  27.  
  28. void        Internal_Update();
  29. word        DataCRC();
  30. word        CalculateGapLength();
  31.  
  32. /*-
  33.  *  The high clock bit in this table is still 0, but it could become
  34.  *  a 1 if the two adjecent data bits are both 0.
  35.  *  In fact, that is the principle of MFM clock bits: make sure that no
  36.  *  two 1 bits are adjecent, but not too many (more than 3) 0 bits either.
  37.  *  So, 0 c 0 -> 0 1 0        (where c is a clock bit to be determined)
  38.  *    0 c 1 -> 0 0 1
  39.  *    1 c 0 -> 1 0 0
  40.  *    1 c 1 -> 1 0 1
  41.  *  The sync pattern, $4489, is %0100 0100 1000 1001
  42.  *                  ~ ~  ~ ~  ~ ~  ~ ~ -> %1010 0001 -> $A1
  43.  *  also follows the rules, but won't be formed by encoding $A1...
  44.  *  Since the bytes are written high bit first, the unknown clock bit
  45.  *  (for encoded nybbles 0-7, high bit 0) will become a 1 if the preceding
  46.  *  byte was even (with low bit 0).
  47.  *  So, the clock bit is the NOR of the two data bits.
  48. -*/
  49.  
  50. byte        MfmEncode[16] = {
  51.     0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15,
  52.     0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55
  53. };
  54.  
  55. #define SYNC    0x4489
  56. #define TLEN    12500        /* In BYTES */
  57. #define RLEN    (TLEN+1324) /* 1 sector extra */
  58. #define WLEN    (TLEN+20)   /* 20 bytes more than the theoretical track size */
  59.  
  60. #define INDEXGAP    40  /* All these values are in WORDS */
  61. #define INDXGAP     12
  62. #define INDXSYNC     3
  63. #define INDXMARK     1
  64. #define INDEXGAP2    40
  65. #define INDEXLEN    (INDEXGAP+INDXGAP+INDXSYNC+INDXMARK+INDEXGAP2)
  66.  
  67. #define IDGAP2        12  /* Sector header: 22 words */
  68. #define IDSYNC         3
  69. #define IDMARK         1
  70. #define IDDATA         4
  71. #define IDCRC         2
  72. #define IDLEN        (IDGAP2+IDSYNC+IDMARK+IDDATA+IDCRC)
  73.  
  74. #define DATAGAP1    22  /* Sector itself: 552 words */
  75. #define DATAGAP2    12
  76. #define DATASYNC     3
  77. #define DATAMARK     1
  78. #define DATACRC      2
  79. #define DATAGAP3_9    78  /* for 9 or less sectors/track */
  80. #define DATAGAP3_10    40  /* for 10 sectors/track */
  81. #define DATALEN     (DATAGAP1+DATAGAP2+DATASYNC+DATAMARK+MS_BPS+DATACRC)
  82.  
  83. #define BLOCKLEN    (IDLEN+DATALEN)     /* Total: 574 words */
  84.  
  85. /* INDENT OFF */
  86. #asm
  87.  
  88. ; Some hardware data:
  89.  
  90. INDEXSYNC    equ $5224    ; special sync for index
  91. SYNC        equ $4489    ; normal sector sync
  92. TLEN        equ 12500    ; 2 miscrosecs/bit, 200 ms/track -> 100000 bits
  93. WLEN        equ TLEN+20
  94.  
  95. ;;;;
  96. ;
  97. ;   The following lengths are all in unencoded bytes (or encoded words)
  98.  
  99. INDEXGAP    equ 40
  100. INDXGAP     equ 12
  101. INDXSYNC    equ  3
  102. INDXMARK    equ  1
  103. INDEXGAP2    equ 40
  104.  
  105. IDGAP2        equ 12
  106. IDSYNC        equ  3
  107. IDMARK        equ  1
  108. IDDATA        equ  4
  109. IDCRC        equ  2
  110.  
  111. DATAGAP1    equ 22
  112. DATAGAP2    equ 12
  113. DATASYNC    equ  3
  114. DATAMARK    equ  1
  115. DATACRC     equ  2
  116.  
  117. custom        equ $DFF000
  118.  
  119. Dsklen        equ $24
  120. Intena        equ $9a     ; Interrupt enable  register (write)
  121. Intreq        equ $9c     ; Interrupt request register (write)
  122.  
  123. ; Flags in DSKLEN:
  124.  
  125. dskdmaoff    equ $4000
  126.  
  127. ; Flags in INTENA/INTREQ:
  128.  
  129. intf_setclr    equ 1<<15
  130. intf_dskblk    equ 1<<1
  131.  
  132. ; CIA interrupt control register bits/flags:
  133.  
  134. ciaicrf_flg    equ    1<<4     ; flg interrupt (disk index)
  135.  
  136. ; some cia.resource library functions
  137.  
  138.         public    _LVOSignal
  139.         public    _LVOAbleICR
  140.         public    _LVOSetICR
  141.  
  142. _SafeEnableICR: move.l    _CiaBResource,a6
  143.         move.b    4+1(sp),d0
  144.         jsr    _LVOSetICR(a6)      ; clear pending interrupt
  145.         move.b    4+1(sp),d0
  146.         or.b    #$80,d0         ; then enable it
  147.         jsr    _LVOAbleICR(a6)
  148.         rts
  149. ;;;;
  150. ;
  151. ;   Disk index interrupt code.
  152. ;   is_Data (A1) is the value to stuff into the DSKLEN register.
  153. ;   A0 points to the custom chips already.
  154. ;   It then enables the disk block interrupt and disables the
  155. ;   index interrupt.
  156.  
  157. _IndexIntCode:
  158. ;     movem.l A2-A4/D2-D7,-(sp)
  159.     move.w    #dskdmaoff,Dsklen(a0)
  160.     move.w    a1,Dsklen(a0)
  161.     move.w    a1,Dsklen(a0)       ; this enables the DMA
  162.     move.w    #intf_setclr|intf_dskblk,Intena(a0)
  163.     move.l    _CiaBResource,a6
  164.     move.b    #ciaicrf_flg,d0
  165.     jsr    _LVOAbleICR(a6)     ; disable index interrupt
  166. ;     movem.l (sp)+,A2-A4/D2-D7
  167.     rts
  168. ;;;;
  169. ;
  170. ;   Disk DMA finished interrupt code.
  171. ;   (a1) is the task to Signal, 4(a1) is the signal mask to use.
  172. ;   Disables the disk block finished interrupt.
  173.  
  174. _DskBlkIntCode:
  175.     move.w    #dskdmaoff,Dsklen(a0)   ; disable disk DMA
  176.     move.w    #intf_dskblk,Intena(a0) ; disable the interrupt
  177.     move.w    #intf_dskblk,Intreq(a0) ; clear 'diskblock finished' flag
  178.     move.l    4(a1),d0            ; signal mask
  179.     move.l    (a1),a1             ; task to signal
  180.     jsr    _LVOSignal(a6)
  181.     rts
  182.  
  183. #endasm
  184.  
  185. #define DSKDMAEN    (1<<15)
  186. #define DSKWRITE    (1<<14)
  187.  
  188. void IndexIntCode(), DskBlkIntCode();
  189.  
  190. /* INDENT ON */
  191.  
  192. int
  193. HardwareIO(dev, unit, dskwrite)
  194. DEV           *dev;
  195. register UNIT  *unit;
  196. int        dskwrite;
  197. {
  198.     struct {
  199.     struct Task *task;
  200.     ulong signal;
  201.     } tasksig;
  202.  
  203.     debug(("Disk buffer is at %lx\n", dev->md_Rawbuffer));
  204.  
  205.     tasksig.task = FindTask(NULL);
  206.     tasksig.signal = 1L << unit->mu_DmaSignal;
  207.  
  208.     unit->mu_DRUnit.dru_Index.is_Data = (APTR) ((WLEN >> 1)|DSKDMAEN| dskwrite);
  209.     unit->mu_DRUnit.dru_DiscBlock.is_Data = (APTR) &tasksig;
  210.  
  211.     /* Clear signal bit */
  212.     SetSignal(0L, tasksig.signal);
  213.  
  214.     /* Allocate drive and install index and block interrupts */
  215.     GetDrive(&unit->mu_DRUnit);
  216.  
  217.     /* Select correct drive and side */
  218.     ciab.ciaprb = 0xff & ~CIAF_DSKMOTOR;    /* See hardware manual p229 */
  219.     ciab.ciaprb = 0xff & ~CIAF_DSKMOTOR
  220.                & ~(CIAF_DSKSEL0 << unit->mu_UnitNr)
  221.                & ~(unit->mu_CurrentSide << CIAB_DSKSIDE);
  222.  
  223.     /* Set up disk parameters */
  224.  
  225. /*
  226.  * This is the adkcon setup: MFM mode, wordsync, no MSBsync, fast mode.
  227.  * The precomp is 0 nanoseconds for the outer half of the disk, 120 for
  228.  * the rest.
  229.  */
  230.     {
  231.     register word adk;
  232.  
  233.     custom.adkcon = ADKF_PRECOMP1|ADKF_PRECOMP0|ADKF_MSBSYNC;
  234.  
  235.     adk = ADKF_SETCLR|ADKF_MFMPREC|ADKF_FAST|ADKF_WORDSYNC;
  236.  
  237.     /* Are we on the inner half ? */
  238.     if (unit->mu_CurrentTrack > unit->mu_NumCyls >> 1) {
  239.         adk |= ADKF_PRECOMP0;
  240.     }
  241.     custom.adkcon = adk;
  242.     }
  243.  
  244.     /* Set up disk buffer address */
  245.     custom.dskpt = (APTR) dev->md_Rawbuffer;
  246.  
  247.     /* Enable disk DMA */
  248.     custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_DISK;
  249.  
  250.     if (dskwrite) {
  251.     /* Enable disk index interrupt to start the whole thing. */
  252.     SafeEnableICR((int) CIAICRF_FLG);
  253.     } else {
  254.     /* Set the sync word */
  255.     custom.dsksync = SYNC;
  256.  
  257.     /* Do the same as the disk index interrupt would */
  258.     custom.dsklen = DSKDMAOFF;
  259.     custom.dsklen = (RLEN >> 1) | DSKDMAEN;
  260.     custom.dsklen = (RLEN >> 1) | DSKDMAEN;
  261.  
  262.     custom.intena = INTF_SETCLR | INTF_DSKBLK;
  263.     }
  264.  
  265.     Wait(tasksig.signal);
  266.  
  267.     FreeDrive();
  268. }
  269.  
  270. #if 0
  271. #define ID_ADDRESS_MARK     0xFE
  272. #define MFM_ID            0x5554
  273. #define DATA_ADDRESS_MARK   0xFB
  274. #define MFM_DATA        0x5545
  275.  
  276. /* INDENT OFF
  277. byte
  278. DecodeByte(mfmdecode, mfm)
  279. byte *mfmdecode;
  280. word mfm;
  281. {
  282.     return mfmdecode[(byte)mfm & 0x7F] |
  283.        mfmdecode[(byte)(mfm >> 8) & 0x7F] << 4;
  284. } */
  285.  
  286. #asm
  287. mfmdecode   set     4
  288. mfm        set     8
  289.  
  290. _DecodeByte:
  291.     move.l    mfmdecode(sp),a0
  292.     move.b    mfm(sp),d1      ; high nybble
  293.     and.w    #$7f,d1     ; strip clock bit (and garbage)
  294.     move.b    (a0,d1.w),d0    ; decode 4 data bits
  295.     lsl.b    #4,d0        ; make room for the rest
  296.  
  297.     move.b    mfm+1(sp),d1    ; low nybble
  298.     and.b    #$7f,d1     ; strip clock bit again
  299.     or.b    (a0,d1.w),d0    ; insert 4 decoded bits
  300.  
  301.     rts
  302.  
  303. #endasm
  304.  
  305. /* INDENT ON */
  306. byte DecodeByte();
  307.  
  308. int
  309. DecodeTrack(dev, unit)
  310. DEV           *dev;
  311. UNIT           *unit;
  312. {
  313.     register word  *rawbuf = (word *)dev->md_Rawbuffer; /*  a2 */
  314.     byte       *rawend = (byte *)rawbuf + RLEN - (MS_BPS+2)*sizeof(word);
  315.     byte       *trackbuf = unit->mu_TrackBuffer;
  316.     register byte  *decode = dev->md_MfmDecode;     /*  a3 */
  317.     word       *oldcrc = unit->mu_CrcBuffer;
  318.     register byte  *secptr;                /*  a4 */
  319.     long        sector;
  320.     word        numsecs;
  321.     register long   numbytes;                /*  d3 */
  322.     word        maxsec;
  323.  
  324. #define Len    ((byte *)rawbuf - dev->md_Rawbuffer)
  325.     maxsec = 0;
  326.  
  327.     for (numsecs = 0; numsecs < MS_SPT_MAX; numsecs++) {
  328.     /*
  329.      *  First try to find a sector id.
  330.      */
  331. find_id:
  332.     while (*rawbuf != SYNC) {
  333.         if (++rawbuf >= rawend) {
  334.         debug(("id start, EOT %4x\n", Len));
  335.         goto end;
  336.         }
  337.     }
  338.     while (*rawbuf == SYNC) {
  339.         rawbuf++;
  340.     }
  341.     if (*rawbuf++ != MFM_ID) {
  342.         debug(("No ID (%4x), %4x\n", rawbuf[-1], Len));
  343.         goto find_id;
  344.     }
  345.  
  346.     sector = DecodeByte(decode, *rawbuf++);
  347.     if (sector != unit->mu_CurrentTrack) {
  348.         debug(("Track error?? %d\n", (int)sector));
  349.         goto find_id;
  350.     }
  351.     sector = DecodeByte(decode, *rawbuf++);
  352.     if (sector != unit->mu_CurrentSide) {
  353.         debug(("Side error?? %d\n", (int)sector));
  354.         goto find_id;
  355.     }
  356.     if (rawbuf >= rawend) {
  357.         debug(("id end, EOT %4x\n", Len));
  358.         goto end;
  359.     }
  360.     sector = DecodeByte(decode, *rawbuf++);
  361.     debug(("#%2d %4x, ", (int)sector, Len-0xC));
  362.     if (sector > MS_SPT_MAX) {
  363.         debug(("Bogus sector number) "));
  364.         goto find_id;
  365.     }
  366.     if (sector > maxsec)
  367.         maxsec = sector;
  368.     sector--;        /* Normalize sector number */
  369.  
  370.     /*
  371.      *  Then find the data block.
  372.      */
  373. find_data:
  374.     while (*rawbuf != SYNC) {
  375.         if (++rawbuf >= rawend) {
  376.         debug(("data start, EOT %4x\n", Len));
  377.         return 0; /* TDERR_TooFewSecs; */
  378.         }
  379.     }
  380.     while (*rawbuf == SYNC) {
  381.         rawbuf++;
  382.     }
  383.     if (*rawbuf++ != MFM_DATA) {
  384.         debug(("No Data (%4x), %4x\n", rawbuf[-1], Len));
  385.         goto find_id;
  386.     }
  387.     debug(("%4x, ", Len-8));
  388.  
  389.     if (rawbuf >= rawend) {
  390.         debug(("short data, EOT %4x\n", Len));
  391.         goto end;
  392.     }
  393.     secptr = trackbuf + MS_BPS * sector;
  394.     for (numbytes = 0; numbytes < MS_BPS; numbytes++) {
  395.         *secptr++ = DecodeByte(decode, *rawbuf++);
  396.     }
  397.     debug(("%4x\n", Len));
  398.     oldcrc[sector]    = DecodeByte(decode, *rawbuf++) << 8;
  399.     oldcrc[sector] |= DecodeByte(decode, *rawbuf++);
  400.     unit->mu_SectorStatus[sector] = unit->mu_InitSectorStatus;
  401.     }
  402.  
  403. end:
  404.     if (numsecs == 0)
  405.     return TDERR_TooFewSecs;
  406.  
  407. #ifndef READONLY
  408.     /*
  409.      * If we read the very first track, we adjust our notion about the
  410.      * number of sectors on each track. This is the only track we can
  411.      * accurately find if this number is unknown. Let's hope that the first
  412.      * user of this disk starts reading it here.
  413.      */
  414.     if (unit->mu_CurrentTrack == 0 && unit->mu_CurrentSide == 0) {
  415.     unit->mu_SectorsPerTrack = maxsec;
  416.     }
  417.     unit->mu_CurrentSectors = maxsec;
  418.     debug(("%d sectors\n", unit->mu_SectorsPerTrack));
  419. #endif
  420.  
  421.     return 0;
  422.  
  423. #undef Len
  424. }
  425. #else    /* Use assembly */
  426.  
  427. int
  428. DecodeTrack(dev, unit)
  429. DEV           *dev;
  430. UNIT           *unit;
  431. {
  432.     register word  *rawbuf = (word *)dev->md_Rawbuffer; /*  a2 */
  433.     byte       *rawend = (byte *)rawbuf + RLEN - (MS_BPS+2)*sizeof(word);
  434.     byte       *trackbuf = unit->mu_TrackBuffer;
  435.     register byte  *decode = dev->md_MfmDecode;     /*  a3 */
  436.     word       *oldcrc = unit->mu_CrcBuffer;
  437.     register byte  *secptr;                /*  a4 */
  438.     long        sector;
  439.     word        numsecs;
  440.     register long   numbytes;                /*  d3 */
  441.     word        maxsec;
  442.  
  443. #asm
  444.  
  445. MFM_ID        equ     $5554
  446. MFM_DATA    equ     $5545
  447.  
  448. rawbuf        equr    a2
  449. decode        equr    a3
  450. secptr        equr    a4
  451. numbytes    equr    d3
  452.  
  453. rawend        set     -4
  454. trackbuf    set     -8
  455. oldcrc        set     -12
  456. sector        set     -16
  457. numsecs     set     -18
  458. maxsec        set     -20
  459.  
  460.     move.w    #0,numsecs(a5)      ; no sectors found yet
  461.     move.w    #0,maxsec(a5)       ; and no highest sector number
  462.  
  463. ;;;;    First we will try to find a sector id.
  464. find_id:
  465.     cmp    #SYNC,(rawbuf)+
  466.     beq.s    fid_gotsync
  467.     cmpa.l    rawend(a5),rawbuf
  468.     blt    find_id
  469.     bra    return            ; We ran off the end of the buffer.
  470.  
  471. fid_gotsync:                ; Skip the other syncs.
  472.     cmp.w    #SYNC,(rawbuf)
  473.     bne    fid_endsync
  474.     lea    2(rawbuf),rawbuf
  475.     bra    fid_gotsync
  476.  
  477. fid_endsync:
  478.     cmp.w    #MFM_ID,(rawbuf)+
  479.     bne    find_id
  480.  
  481.     bsr    DecodeByte        ; track #
  482.     bsr    DecodeByte        ; side #
  483.     moveq.l #0,d0            ; clear high part
  484.     bsr    DecodeByte        ; sector #
  485.     cmp.w    #MS_SPT_MAX,d0        ; sector number too large?
  486.     bgt    find_id
  487.     cmp.w    maxsec(a5),d0       ; what is the highest sector number?
  488.     ble    nomax
  489.     move.w    d0,maxsec(a5)       ; record the highest sector number
  490. nomax:
  491.     subq.w    #1,d0            ; normalize sector number
  492.     move.l    d0,sector(a5)
  493.  
  494. find_data:                ; Then find the data block.
  495.     cmp    #SYNC,(rawbuf)+
  496.     beq.s    fda_gotsync
  497.     cmpa.l    rawend(a5),rawbuf
  498.     blt    find_data
  499.     bra    return            ; we ran off the end of the buffer.
  500.  
  501. fda_gotsync:                ; skip the other syncs.
  502.     cmp.w    #SYNC,(rawbuf)
  503.     bne    fda_endsync
  504.     lea    2(rawbuf),rawbuf
  505.     bra    fda_gotsync
  506.  
  507. fda_endsync:
  508.     cmp.w    #MFM_DATA,(rawbuf)+ ; do we really have a data block?
  509.     bne    find_id
  510.  
  511.     cmpa.l    rawend(a5),rawbuf   ; will we still be inside the mfm data?
  512.     bge    return
  513.  
  514.     move.l    sector(a5),d0       ; calculate the location to
  515.     moveq.l #LOG2_MS_BPS,d1     ;  store this sector.
  516.     asl.l    d1,d0
  517.     move.l    trackbuf(a5),secptr
  518.     add.l    d0,secptr
  519.  
  520.     move.w    #MS_BPS-1,numbytes
  521. data_copy:
  522.     bsr    DecodeByte
  523.     move.b    d0,(secptr)+
  524.     dbra    numbytes,data_copy
  525.  
  526.     move.l    sector(a5),d3       ; get pointer to crc location
  527.     add.l    d3,d3            ; 2 bytes of crc per sector
  528.     move.l    oldcrc(a5),a0
  529.     add.l    d3,a0
  530.  
  531.     bsr    DecodeByte        ; get high byte
  532.     move.b    d0,(a0)+
  533.     bsr    DecodeByte        ; and low byte of crc
  534.     move.b    d0,(a0)+
  535.  
  536. #endasm
  537.     unit->mu_SectorStatus[sector] = unit->mu_InitSectorStatus;
  538. #asm
  539.     addq.w    #1,numsecs(a5)
  540.     cmp.w    #MS_SPT_MAX,numsecs(a5)
  541.     blt    find_id
  542. return:
  543. #endasm
  544.  
  545.     if (numsecs == 0)
  546.     return TDERR_TooFewSecs;
  547.  
  548. #ifndef READONLY
  549.     /*
  550.      * If we read the very first track, we adjust our notion about the
  551.      * number of sectors on each track. This is the only track we can
  552.      * accurately find if this number is unknown. Let's hope that the first
  553.      * user of this disk starts reading it here.
  554.      */
  555.     if (unit->mu_CurrentTrack == 0 && unit->mu_CurrentSide == 0) {
  556.     unit->mu_SectorsPerTrack = maxsec;
  557.     }
  558.     unit->mu_CurrentSectors = maxsec;
  559.     debug(("%d sectors\n", unit->mu_SectorsPerTrack));
  560. #endif
  561.  
  562.     return 0;
  563.  
  564. }
  565.  
  566. #asm
  567. ;;;;
  568. ;
  569. ;   Decode a single MFM word to a byte.
  570. ;   Auto-increments the rawbuffer pointer.
  571.  
  572. DecodeByte:
  573.     move.b    (rawbuf)+,d1    ; high nybble
  574.     and.w    #$7f,d1     ; strip clock bit (and garbage)
  575.     move.b    (decode,d1.w),d0; decode 4 data bits
  576.     lsl.b    #4,d0        ; make room for the rest
  577.  
  578.     move.b    (rawbuf)+,d1    ; low nybble
  579.     and.b    #$7f,d1     ; strip clock bit again
  580.     or.b    (decode,d1.w),d0; insert 4 decoded bits
  581.  
  582.     rts
  583.  
  584. #endasm
  585. #endif    /* using assembly */
  586.  
  587. /*
  588.  * Initialize the ibm mfm decoding table
  589.  */
  590.  
  591. void
  592. InitDecoding(decode)
  593. register byte  *decode;
  594. {
  595.     register int    i;
  596.  
  597.     i = 0;
  598.     do {
  599.     decode[i] = 0xff;
  600.     } while (++i < 128);
  601.  
  602.     i = 0;
  603.     do {
  604.     decode[MfmEncode[i]] = i;
  605.     } while (++i < 0x10);
  606. }
  607.  
  608. #ifdef notdef
  609. long
  610. MyDoIO(req)
  611. register struct IORequest *req;
  612. {
  613.     req->io_Flags |= IOF_QUICK;
  614.     BeginIO(req);
  615.     return WaitIO(req);
  616. }
  617. #endif
  618.  
  619. /*
  620.  * Switch the drive motor on. Return previous state. Don't use this when
  621.  * you have allocated the disk via GetDrive().
  622.  */
  623.  
  624. int
  625. TDMotorOn(tdreq)
  626. register struct IOExtTD *tdreq;
  627. {
  628.     debug(("TDMotorOn "));
  629.     tdreq->iotd_Req.io_Command = TD_MOTOR;
  630.     tdreq->iotd_Req.io_Length = 1;
  631.     DoIO(tdreq);
  632.     debug(("was %ld\n", tdreq->iotd_Req.io_Actual));
  633.  
  634.     return tdreq->iotd_Req.io_Actual;
  635. }
  636.  
  637. /*
  638.  * Get the number of cylinders the drive is capable of using.
  639.  */
  640.  
  641. int
  642. TDGetNumCyls(tdreq)
  643. register struct IOExtTD *tdreq;
  644. {
  645.     tdreq->iotd_Req.io_Command = TD_GETNUMTRACKS;
  646.     DoIO(tdreq);
  647.  
  648.     return tdreq->iotd_Req.io_Actual / NUMHEADS;
  649. }
  650.  
  651. /*
  652.  * Seek the drive to the indicated cylinder. Use the trackdisk.device for
  653.  * ease. Don't use this when you have allocated the disk via GetDrive().
  654.  */
  655.  
  656. int
  657. TDSeek(unit, ioreq, cylinder)
  658. UNIT           *unit;
  659. struct IOStdReq *ioreq;
  660. int        cylinder;
  661. {
  662.     register struct IOExtTD *tdreq = unit->mu_DiskIOReq;
  663.  
  664.     debug(("TDSeek %d\n", cylinder));
  665.  
  666.     tdreq->iotd_Req.io_Command = TD_SEEK;
  667.     tdreq->iotd_Req.io_Offset = cylinder * (TD_SECTOR * NUMSECS * NUMHEADS);
  668.     if ((ioreq->io_Flags & IOMDF_40TRACKS) && (unit->mu_NumCyls == 80))
  669.     tdreq->iotd_Req.io_Offset *= 2;
  670.     DoIO(tdreq);
  671.  
  672.     return tdreq->iotd_Req.io_Error;
  673. }
  674.  
  675. void           *
  676. GetDrive(drunit)
  677. register struct DiskResourceUnit *drunit;
  678. {
  679.     register void  *LastDriver;
  680.  
  681.     debug(("GetDrive: "));
  682.     for (;;) {
  683.     drunit->dru_Message.mn_Node.ln_Type = NT_MESSAGE;
  684.     LastDriver = GetUnit(drunit);
  685.  
  686.     debug(("LastDriver %08lx\n", LastDriver));
  687.     if (LastDriver) {
  688.         return LastDriver;
  689.     } else {
  690.         while (drunit->dru_Message.mn_Node.ln_Type != NT_REPLYMSG)
  691.         Wait(1L << drunit->dru_Message.mn_ReplyPort->mp_SigBit);
  692.         Remove(drunit);
  693.         debug(("GetDrive: Retry\n"));
  694.     }
  695.     }
  696. }
  697.  
  698. void
  699. FreeDrive()
  700. {
  701.     GiveUnit();
  702. }
  703.  
  704. int
  705. GetTrack(ioreq, side, track)
  706. struct IOStdReq *ioreq;
  707. int        side;
  708. int        track;
  709. {
  710.     register int    i;
  711.     DEV        *dev;
  712.     register UNIT  *unit;
  713.  
  714.     debug(("GetTrack %d %d\n", track, side));
  715.     dev = (DEV *) ioreq->io_Device;
  716.     unit = (UNIT *) ioreq->io_Unit;
  717.  
  718.     if (track != unit->mu_CurrentTrack || side != unit->mu_CurrentSide) {
  719. #ifndef READONLY
  720.     Internal_Update(ioreq, unit);
  721. #endif
  722.     for (i = MS_SPT_MAX-1; i >= 0; i--) {
  723.         unit->mu_SectorStatus[i] = TDERR_NoSecHdr;
  724.     }
  725.  
  726.     TDMotorOn(unit->mu_DiskIOReq);
  727.     if (TDSeek(unit, ioreq, track)) {
  728.         debug(("Seek error\n"));
  729.         return ioreq->io_Error = IOERR_BADLENGTH;
  730.     }
  731.     unit->mu_CurrentTrack = track;
  732.     unit->mu_CurrentSide = side;
  733.     ObtainSemaphore(&dev->md_HardwareUse);
  734.     HardwareIO(dev, unit, 0);
  735.     i = DecodeTrack(dev, unit);
  736.     ReleaseSemaphore(&dev->md_HardwareUse);
  737.     debug(("DecodeTrack returns %d\n", i));
  738.  
  739.     if (i != 0) {
  740.         unit->mu_CurrentTrack = -1;
  741.         return i;
  742.     }
  743.     }
  744.  
  745.     return 0;
  746. }
  747.  
  748. /*
  749.  * Test if it is changed
  750.  */
  751.  
  752. int
  753. CheckChanged(ioreq, unit)
  754. struct IOExtTD *ioreq;
  755. register UNIT  *unit;
  756. {
  757.     register struct IOExtTD *tdreq;
  758.  
  759.     if ((ioreq->iotd_Req.io_Command & TDF_EXTCOM) &&
  760.     ioreq->iotd_Count < unit->mu_ChangeNum) {
  761. diskchanged:
  762.     ioreq->iotd_Req.io_Error = TDERR_DiskChanged;
  763. error:
  764.     return 1;
  765.     }
  766.     return 0;
  767. }
  768.  
  769. /*
  770.  * Test if we can read or write the disk. Is it inserted and writable?
  771.  */
  772.  
  773. int
  774. CheckRequest(ioreq, unit)
  775. struct IOExtTD *ioreq;
  776. register UNIT  *unit;
  777. {
  778.     register struct IOExtTD *tdreq;
  779.  
  780.     if ((ioreq->iotd_Req.io_Command & TDF_EXTCOM) &&
  781.     ioreq->iotd_Count < unit->mu_ChangeNum) {
  782. diskchanged:
  783.     ioreq->iotd_Req.io_Error = TDERR_DiskChanged;
  784. error:
  785.     return 1;
  786.     }
  787.     /*
  788.      * if (ioreq->iotd_Req.io_Offset + ioreq->iotd_Req.io_Length >
  789.      * (unit->mu_NumCyls * MS_NSIDES * MS_SPT * MS_BPS)) {
  790.      * ioreq->iotd_Req.io_Error = IOERR_BADLENGTH; goto error; }
  791.      */
  792.  
  793.     tdreq = unit->mu_DiskIOReq;
  794.  
  795.     if (unit->mu_DiskState == STATEF_UNKNOWN) {
  796.     tdreq->iotd_Req.io_Command = TD_PROTSTATUS;
  797.     DoIO(tdreq);
  798.     if (tdreq->iotd_Req.io_Error == 0) {
  799.         if (tdreq->iotd_Req.io_Actual == 0) {
  800.         unit->mu_DiskState = STATEF_PRESENT | STATEF_WRITABLE;
  801.         } else
  802.         unit->mu_DiskState = STATEF_PRESENT;
  803.     } else
  804.         unit->mu_DiskState = 0;
  805.     }
  806.     if (!(unit->mu_DiskState & STATEF_PRESENT))
  807.     goto diskchanged;
  808.  
  809.     /*
  810.      * Check _WRITE, _UPDATE, _FORMAT
  811.      */
  812.     if (STRIP(ioreq->iotd_Req.io_Command) != CMD_READ) {
  813.     if (!(unit->mu_DiskState & STATEF_WRITABLE)) {
  814.         ioreq->iotd_Req.io_Error = TDERR_WriteProt;
  815.         goto error;
  816.     }
  817.     }
  818.     return 0;
  819. }
  820.  
  821.  
  822. /*
  823.  * Read zero or more sectors from the disk and copy them into the user's
  824.  * buffer.
  825.  */
  826.  
  827. void
  828. CMD_Read(ioreq, unit)
  829. register struct IOExtTD *ioreq;
  830. register UNIT  *unit;
  831. {
  832.     int         side;
  833.     int         cylinder;
  834.     int         sector;
  835.     byte       *userbuf;
  836.     long        length;
  837.     long        offset;
  838.     byte       *diskbuf;
  839.     int         retrycount;
  840.  
  841.     debug(("CMD_Read "));
  842.     userbuf = (byte *) ioreq->iotd_Req.io_Data;
  843.     length = ioreq->iotd_Req.io_Length / MS_BPS;    /* Sector count */
  844.     offset = ioreq->iotd_Req.io_Offset / MS_BPS;    /* Sector number */
  845.     debug(("userbuf %08lx off %ld len %ld ", userbuf, offset, length));
  846.  
  847.     cylinder = offset / unit->mu_SectorsPerTrack;
  848.     side = cylinder % MS_NSIDES;
  849.     cylinder /= MS_NSIDES;
  850.     sector = offset % unit->mu_SectorsPerTrack;       /* 0..8 or 9 */
  851.     debug(("Tr=%d Si=%d Se=%d\n", cylinder, side, sector));
  852.  
  853.     ioreq->iotd_Req.io_Actual = 0;
  854.  
  855.     if (length <= 0 || CheckRequest(ioreq, unit))
  856.     goto end;
  857.  
  858.     retrycount = 0;
  859.     diskbuf = unit->mu_TrackBuffer + MS_BPS * sector;
  860. gettrack:
  861.     GetTrack(ioreq, side, cylinder);
  862.  
  863.     for (;;) {
  864.     /*
  865.      * Have we ever checked this CRC?
  866.      */
  867.     if (unit->mu_SectorStatus[sector] == CRC_UNCHECKED) {
  868.         /*
  869.          * Do it now. If it mismatches, remember that for later.
  870.          */
  871.         if (unit->mu_CrcBuffer[sector] != DataCRC(diskbuf)) {
  872.         debug(("%d: %04x, now %04x\n", sector, unit->mu_CrcBuffer[sector], DataCRC(diskbuf)));
  873.         unit->mu_SectorStatus[sector] = TDERR_BadSecSum;
  874.         } else
  875.         unit->mu_SectorStatus[sector] = TDERR_NoError;
  876.     }
  877.     if (unit->mu_SectorStatus[sector] > TDERR_NoError) {
  878.         if (++retrycount < 3) {
  879.         unit->mu_CurrentTrack = -1;
  880.         goto gettrack;
  881.         }
  882.         ioreq->iotd_Req.io_Error = unit->mu_SectorStatus[sector];
  883.         goto end;        /* Don't use this sector anymore... */
  884.     }
  885.     retrycount = 0;
  886.     CopyMem(diskbuf, userbuf, (long) MS_BPS);
  887.     ioreq->iotd_Req.io_Actual += MS_BPS;
  888.     if (--length <= 0)
  889.         break;
  890.     userbuf += MS_BPS;
  891.     diskbuf += MS_BPS;
  892.     if (++sector >= unit->mu_SectorsPerTrack) {
  893.         sector = 0;
  894.         diskbuf = unit->mu_TrackBuffer;
  895.         if (++side >= MS_NSIDES) {
  896.         side = 0;
  897.         if (++cylinder >= unit->mu_NumCyls) {
  898.             /* ioreq->iotd_Req.io_Error = IOERR_BADLENGTH; */
  899.             goto end;
  900.         }
  901.         }
  902.         GetTrack(ioreq, side, cylinder);
  903.     }
  904.     }
  905.  
  906. end:
  907.     TermIO(ioreq);
  908. }
  909.  
  910. #ifdef READONLY
  911.  
  912. void
  913. CMD_Write(ioreq, unit)
  914. register struct IOExtTD *ioreq;
  915. UNIT           *unit;
  916. {
  917.     ioreq->iotd_Req.io_Error = TDERR_NotSpecified;
  918.     TermIO(ioreq);
  919. }
  920.  
  921. void
  922. TD_Format(ioreq, unit)
  923. register struct IOExtTD *ioreq;
  924. UNIT           *unit;
  925. {
  926.     ioreq->iotd_Req.io_Error = TDERR_NotSpecified;
  927.     TermIO(ioreq);
  928. }
  929.  
  930. #endif
  931.  
  932. void
  933. CMD_Reset(ioreq, unit)
  934. struct IOExtTD *ioreq;
  935. UNIT           *unit;
  936. {
  937.     unit->mu_CurrentSide = -1;
  938.     unit->mu_TrackChanged = 0;
  939.     TermIO(ioreq);
  940. }
  941.  
  942. void
  943. CMD_Update(ioreq, unit)
  944. struct IOExtTD *ioreq;
  945. register UNIT  *unit;
  946. {
  947. #ifndef READONLY
  948.     if (unit->mu_TrackChanged && !CheckRequest(ioreq, unit))
  949.     Internal_Update(ioreq, unit);
  950. #endif
  951.     TermIO(ioreq);
  952. }
  953.  
  954. void
  955. CMD_Clear(ioreq, unit)
  956. struct IOExtTD *ioreq;
  957. UNIT           *unit;
  958. {
  959.     if (!CheckChanged(ioreq, unit)) {
  960.     unit->mu_CurrentSide = -1;
  961.     unit->mu_TrackChanged = 0;
  962.     }
  963.     TermIO(ioreq);
  964. }
  965.  
  966. void
  967. TD_Seek(ioreq, unit)
  968. struct IOExtTD *ioreq;
  969. UNIT           *unit;
  970. {
  971.     if (!CheckChanged(ioreq, unit)) {
  972.     word        cylinder;
  973.  
  974.     cylinder = (ioreq->iotd_Req.io_Offset / unit->mu_SectorsPerTrack) /
  975.             (MS_BPS * MS_NSIDES);
  976.     TDSeek(unit, ioreq, cylinder);
  977.     }
  978.     TermIO(ioreq);
  979. }
  980.  
  981. /*
  982.  * Ask the trackdisk.device for the answer, but keep a local copy.
  983.  */
  984.  
  985. void
  986. TD_Changenum(ioreq, unit)
  987. struct IOExtTD *ioreq;
  988. UNIT           *unit;
  989. {
  990.     register struct IOStdReq *req;
  991.  
  992.     req = &unit->mu_DiskIOReq->iotd_Req;
  993.     req->io_Command = TD_CHANGENUM;
  994.     DoIO(req);
  995.  
  996.     unit->mu_ChangeNum = req->io_Actual;
  997.     ioreq->iotd_Req.io_Actual = req->io_Actual;
  998.     TermIO(ioreq);
  999. }
  1000.  
  1001. int
  1002. DevInit(dev)
  1003. register DEV   *dev;
  1004. {
  1005.     if (!(DRResource = OpenResource(DISKNAME)))
  1006.     goto abort;
  1007.  
  1008.     if (!(CiaBResource = OpenResource(CIABNAME)))
  1009.     goto abort;
  1010.  
  1011. #ifndef READONLY
  1012.     if (!InitWrite(dev))
  1013.     goto abort;
  1014. #endif
  1015.  
  1016.     InitDecoding(dev->md_MfmDecode);
  1017.     InitSemaphore(&dev->md_HardwareUse);
  1018.     return 1;            /* Initializing succeeded */
  1019.  
  1020. abort:
  1021.     return DevCloseDown(dev);
  1022. }
  1023.  
  1024. int
  1025. DevCloseDown(dev)
  1026. DEV           *dev;
  1027. {
  1028. #ifndef READONLY
  1029.     FreeBuffer(dev);
  1030. #endif
  1031.     return 0;            /* Now unitialized */
  1032. }
  1033.  
  1034. #ifndef READONLY
  1035. /*
  1036.  * Calculate the length between the sectors, given the length of the track
  1037.  * and the number of sectors that must fit on it.
  1038.  * The proper formula would be
  1039.  * (((TLEN/2) - INDEXLEN) / unit->mu_SectorsPerTrack) - BLOCKLEN;
  1040.  */
  1041.  
  1042. word
  1043. CalculateGapLength(sectors)
  1044. int        sectors;
  1045. {
  1046.     return (sectors == 10) ? DATAGAP3_10 : DATAGAP3_9;
  1047. }
  1048. #endif
  1049.  
  1050. UNIT           *
  1051. UnitInit(dev, UnitNr)
  1052. DEV           *dev;
  1053. ulong        UnitNr;
  1054. {
  1055.     register UNIT  *unit;
  1056.     struct Task    *task;
  1057.     struct IOStdReq *dcr;
  1058.     struct IOExtTD *tdreq;
  1059.  
  1060.     unit = AllocMem((long) sizeof (UNIT), MEMF_PUBLIC | MEMF_CLEAR);
  1061.     if (unit == NULL)
  1062.     return NULL;
  1063.  
  1064.     if (!(tdreq = CreateExtIO(&unit->mu_DiskReplyPort, (long) sizeof (*tdreq)))) {
  1065.     goto abort;
  1066.     }
  1067.     unit->mu_DiskIOReq = tdreq;
  1068.     if (OpenDevice(TD_NAME, UnitNr, tdreq, TDF_ALLOW_NON_3_5)) {
  1069.     tdreq->iotd_Req.io_Device = NULL;
  1070.     goto abort;
  1071.     }
  1072.     dcr = (void *) CreateExtIO(&unit->mu_DiskReplyPort, (long) sizeof (*dcr));
  1073.     if (dcr) {
  1074.     unit->mu_DiskChangeReq = dcr;
  1075.     unit->mu_DiskChangeInt.is_Node.ln_Pri = 32;
  1076.     unit->mu_DiskChangeInt.is_Data = (APTR) unit;
  1077.     unit->mu_DiskChangeInt.is_Code = DiskChangeHandler;
  1078.     /* Clone IO request part */
  1079.     dcr->io_Device = tdreq->iotd_Req.io_Device;
  1080.     dcr->io_Unit = tdreq->iotd_Req.io_Unit;
  1081.     dcr->io_Command = TD_ADDCHANGEINT;
  1082.     dcr->io_Data = (void *) &unit->mu_DiskChangeInt;
  1083.     SendIO(dcr);
  1084.     }
  1085.     NewList(&unit->mu_ChangeIntList);
  1086.  
  1087.     unit->mu_NumCyls = TDGetNumCyls(tdreq);
  1088.     unit->mu_UnitNr = UnitNr;
  1089.     unit->mu_DiskState = STATEF_UNKNOWN;
  1090.     unit->mu_CurrentSide = -1;
  1091.     unit->mu_TrackChanged = 0;
  1092.     unit->mu_InitSectorStatus = CRC_UNCHECKED;
  1093.     unit->mu_SectorsPerTrack = MS_SPT;
  1094.  
  1095.     unit->mu_DRUnit.dru_Message.mn_ReplyPort = &unit->mu_DiskReplyPort;
  1096.     unit->mu_DRUnit.dru_Index.is_Node.ln_Pri = 32; /* high pri for index int */
  1097.     unit->mu_DRUnit.dru_Index.is_Code = IndexIntCode;
  1098.     unit->mu_DRUnit.dru_DiscBlock.is_Code = DskBlkIntCode;
  1099.  
  1100.     /*
  1101.      * Now create the Unit task. Remember that it won't start running
  1102.      * since we are Forbid()den. But just to be sure, we Forbid() again.
  1103.      */
  1104.     Forbid();
  1105.     task = CreateTask(DevName, TASKPRI, UnitTask, TASKSTACK);
  1106.     task->tc_UserData = (APTR) unit;
  1107.  
  1108.     unit->mu_Port.mp_Flags = PA_IGNORE;
  1109.     unit->mu_Port.mp_SigTask = task;
  1110.     NewList(&unit->mu_Port.mp_MsgList);
  1111.  
  1112.     unit->mu_DiskReplyPort.mp_Flags = PA_IGNORE;
  1113.     unit->mu_DiskReplyPort.mp_SigTask = task;
  1114.     NewList(&unit->mu_DiskReplyPort.mp_MsgList);
  1115.     Permit();
  1116.  
  1117.     return unit;
  1118.  
  1119. abort:
  1120.     UnitCloseDown(NULL, dev, unit);
  1121.     return NULL;
  1122. }
  1123.  
  1124. int
  1125. UnitCloseDown(ioreq, dev, unit)
  1126. struct IOExtTD *ioreq;
  1127. DEV           *dev;
  1128. register UNIT  *unit;
  1129. {
  1130.     /*
  1131.      * Get rid of the Unit's task. We know this is safe because the unit
  1132.      * has an open count of zero, so it is 'guaranteed' not in use.
  1133.      */
  1134.  
  1135.     if (unit->mu_Port.mp_SigTask) {
  1136. #ifdef DEBUG
  1137.     extern struct SignalSemaphore PortUse;
  1138.  
  1139.     /*
  1140.      * Make sure that the unit task does not get removed when it has
  1141.      * the semaphore.
  1142.      */
  1143.     ObtainSemaphore(&PortUse);
  1144. #endif
  1145.     RemTask(unit->mu_Port.mp_SigTask);
  1146. #ifdef DEBUG
  1147.     ReleaseSemaphore(&PortUse);
  1148. #endif
  1149.     }
  1150.     if (unit->mu_DiskChangeReq) {
  1151. #if 0                /* V1.2 and V1.3 have a broken
  1152.                  * TD_REMCHANGEINT */
  1153.     register struct IOExtTD *req = unit->mu_DiskIOReq;
  1154.  
  1155.     req->iotd_Req.io_Command = TD_REMCHANGEINT;
  1156.     req->iotd_Req.io_Data = (void *) unit->mu_DiskChangeReq;
  1157.     DoIO(req);
  1158.     WaitIO(unit->mu_DiskChangeReq);
  1159. #else
  1160.     Disable();
  1161.     Remove(unit->mu_DiskChangeReq);
  1162.     Enable();
  1163. #endif
  1164.     DeleteExtIO(unit->mu_DiskChangeReq);
  1165.     unit->mu_DiskChangeReq = NULL;
  1166.     }
  1167.     if (unit->mu_DiskIOReq) {
  1168.     if (unit->mu_DiskIOReq->iotd_Req.io_Device)
  1169.         CloseDevice(unit->mu_DiskIOReq);
  1170.     DeleteExtIO(unit->mu_DiskIOReq);
  1171.     unit->mu_DiskIOReq = NULL;
  1172.     }
  1173.     FreeMem(unit, (long) sizeof (UNIT));
  1174.  
  1175.     return 0;            /* Now unitialized */
  1176. }
  1177.  
  1178. /*
  1179.  * Create missing bindings
  1180.  */
  1181. /* INDENT OFF */
  1182.  
  1183. #asm
  1184.  
  1185. lib_vectsize    equ    6
  1186. lib_base    equ    -lib_vectsize
  1187.  
  1188. _RVOAllocUnit    equ    lib_base-(0*lib_vectsize)
  1189. _RVOFreeUnit    equ    lib_base-(1*lib_vectsize)
  1190. _RVOGetUnit    equ    lib_base-(2*lib_vectsize)
  1191. _RVOGiveUnit    equ    lib_base-(3*lib_vectsize)
  1192. _RVOGetUnitID    equ    lib_base-(4*lib_vectsize)
  1193.  
  1194. ;_AllocUnit:
  1195. ;        move.l    _DRResource,a6
  1196. ;        move.l    4(sp),d0
  1197. ;        jmp    _RVOAllocUnit(a6)
  1198. ;_FreeUnit:
  1199. ;        move.l    _DRResource,a6
  1200. ;        move.l    4(sp),d0
  1201. ;        jmp    _RVOFreeUnit(a6)
  1202. _GetUnit:
  1203.         move.l    _DRResource,a6
  1204.         move.l    4(sp),a1
  1205.         jmp    _RVOGetUnit(a6)
  1206. ;_GetUnitID:
  1207. ;        move.l    _DRResource,a6
  1208. ;        move.l    4(sp),d0
  1209. ;        jmp    _RVOGetUnitID(a6)
  1210. _GiveUnit:
  1211.         move.l    _DRResource,a6
  1212.         jmp    _RVOGiveUnit(a6)
  1213.  
  1214. #endasm
  1215. /* INDENT ON */
  1216.  
  1217. /*
  1218.  * We handle disk change interrupts internally, since the io request is
  1219.  * held by the device. Since SoftInts caused by the trackdisk.device are
  1220.  * broadcast to our clients, our own softint must have the highest
  1221.  * priority possible.
  1222.  *
  1223.  * TD_Addchangeint is an IMMEDIATE command, so no exclusive use of the list
  1224.  * is acquired (nor released). The list is accessed by (software)
  1225.  * interrupt code.
  1226.  */
  1227.  
  1228. void
  1229. TD_Addchangeint(ioreq)
  1230. register struct IOStdReq *ioreq;
  1231. {
  1232.     register UNIT  *unit;
  1233.  
  1234.     unit = (UNIT *) ioreq->io_Unit;
  1235.     Disable();
  1236.     AddTail(&unit->mu_ChangeIntList, ioreq);
  1237.     Enable();
  1238.     ioreq->io_Flags &= ~IOF_QUICK;    /* So we call ReplyMsg instead of
  1239.                      * TermIO */
  1240.     /* Note no TermIO */
  1241. }
  1242.  
  1243. void
  1244. TD_Remchangeint(ioreq)
  1245. register struct IOStdReq *ioreq;
  1246. {
  1247.     register struct IOStdReq *intreq;
  1248.  
  1249.     intreq = (struct IOStdReq *) ioreq->io_Data;
  1250.     Disable();
  1251.     Remove(intreq);
  1252.     Enable();
  1253.     ReplyMsg(&intreq->io_Message);      /* Quick bit always cleared */
  1254.     ioreq->io_Error = 0;
  1255.     TermIO(ioreq);
  1256. }
  1257.  
  1258. void
  1259. DiskChangeHandler()
  1260. {
  1261.     auto UNIT       *unit;
  1262.     register struct IOStdReq *ioreq;
  1263.     register struct IOStdReq *next;
  1264. /* INDENT OFF */
  1265. #asm
  1266.     movem.l d2-d7/a2-a4,-(sp)
  1267.     move.l  a1,-4(a5)        ;unit
  1268. #endasm
  1269.     /* INDENT ON */
  1270.     unit->mu_DiskState = STATEF_UNKNOWN;
  1271.     unit->mu_ChangeNum++;
  1272.     unit->mu_SectorsPerTrack = MS_SPT;
  1273.     for (ioreq = (struct IOStdReq *) unit->mu_ChangeIntList.mlh_Head;
  1274.      next = (struct IOStdReq *) ioreq->io_Message.mn_Node.ln_Succ;
  1275.      ioreq = next) {
  1276.     Cause((struct Interrupt *) ioreq->io_Data);
  1277.     }
  1278. /* INDENT OFF */
  1279. #asm
  1280.     movem.l (sp)+,d2-d7/a2-a4
  1281. #endasm
  1282.     /* INDENT ON */
  1283. }
  1284.  
  1285. #ifndef READONLY
  1286.  
  1287. /*
  1288.  * Parts of the following code were written by Werner Guenther.
  1289.  * Used with permission.
  1290.  */
  1291.  
  1292. /* mu_TrackChanged is a flag. When a sector has changed it changes to 1 */
  1293.  
  1294. /*
  1295.  * InitWrite() has to be called once at startup. It allocates the space
  1296.  * for one raw track, and writes the low level stuff between sectors
  1297.  * (gaps, syncs etc.)
  1298.  */
  1299.  
  1300. int
  1301. InitWrite(dev)
  1302. DEV           *dev;
  1303. {
  1304.     if ((dev->md_Rawbuffer =
  1305.         AllocMem((long)RLEN+2, MEMF_CHIP | MEMF_PUBLIC)) == 0)
  1306.     return 0;
  1307.  
  1308.     return 1;
  1309. }
  1310.  
  1311. /*
  1312.  * FreeBuffer has to be called when msh: closes down, it just frees the
  1313.  * memory InitWrite has allocated
  1314.  */
  1315.  
  1316. void
  1317. FreeBuffer(dev)
  1318. DEV           *dev;
  1319. {
  1320.     if (dev->md_Rawbuffer) {    /* OIS */
  1321.     FreeMem(dev->md_Rawbuffer, (long) RLEN + 2);
  1322.     }
  1323. }
  1324.  
  1325. /*
  1326.  * This routine doesn't write to the disk, but updates the TrackBuffer to
  1327.  * respect the new sector. We have to be sure the TrackBuffer is filled
  1328.  * with the current Track. As GetSTS calls Internal_Update if the track
  1329.  * changes we don't have to bother about actually writing any data to the
  1330.  * disk. GetSTS has to be changed in the following way:
  1331.  *
  1332.  * if (track != mu_CurrentTrack || side != mu_CurrentSide) { Internal_Update(); for
  1333.  * (i = 0; i < MS_SPT; i++) ..... etc.
  1334.  */
  1335.  
  1336. void
  1337. CMD_Write(ioreq, unit)
  1338. register struct IOExtTD *ioreq;
  1339. UNIT           *unit;
  1340. {
  1341.     int         side;
  1342.     int         cylinder;
  1343.     int         sector;
  1344.     byte       *userbuf;
  1345.     long        length;
  1346.     long        offset;
  1347.     word        spt;
  1348.  
  1349.     debug(("CMD_Write "));
  1350.     userbuf = (byte *) ioreq->iotd_Req.io_Data;
  1351.     length = ioreq->iotd_Req.io_Length / MS_BPS;    /* Sector count */
  1352.     offset = ioreq->iotd_Req.io_Offset / MS_BPS;    /* Sector number */
  1353.     debug(("userbuf %08lx off %ld len %ld ", userbuf, offset, length));
  1354.  
  1355.     spt = unit->mu_SectorsPerTrack;
  1356.     cylinder = offset / spt;
  1357.     side = cylinder % MS_NSIDES;
  1358.     cylinder /= MS_NSIDES;
  1359.     sector = offset % spt;
  1360.     debug(("T=%d Si=%d Se=%d\n", cylinder, side, sector));
  1361.  
  1362.     ioreq->iotd_Req.io_Actual = 0;
  1363.  
  1364.     if (length <= 0 || CheckRequest(ioreq, unit))
  1365.     goto end;
  1366.  
  1367.     GetTrack(ioreq, side, cylinder);
  1368.     for (;;) {
  1369.     CopyMem(userbuf, unit->mu_TrackBuffer + MS_BPS * sector, (long) MS_BPS);
  1370.     unit->mu_TrackChanged = 1;
  1371.     unit->mu_SectorStatus[sector] = CRC_CHANGED;
  1372.  
  1373.     ioreq->iotd_Req.io_Actual += MS_BPS;
  1374.     if (--length <= 0)
  1375.         break;
  1376.     userbuf += MS_BPS;
  1377.     /*
  1378.      * Get next sequential sector/side/track
  1379.      */
  1380.     if (++sector >= spt) {
  1381.         sector = 0;
  1382.         if (++side >= MS_NSIDES) {
  1383.         side = 0;
  1384.         if (++cylinder >= unit->mu_NumCyls)
  1385.             goto end;
  1386.         }
  1387.         GetTrack(ioreq, side, cylinder);
  1388.     }
  1389.     }
  1390.  
  1391.     if (length)
  1392.     ioreq->iotd_Req.io_Error = TDERR_NotSpecified;
  1393.  
  1394. end:
  1395.     TermIO(ioreq);
  1396. }
  1397.  
  1398. /*
  1399.  * This is called by your GetSTS() routine if the Track has changed. It
  1400.  * writes the changes back to the disk (a whole track at a time). It has
  1401.  * to be called if your device gets a CLOSE instruction too.
  1402.  */
  1403.  
  1404. void
  1405. Internal_Update(ioreq, unit)
  1406. struct IOExtTD *ioreq;
  1407. register UNIT  *unit;
  1408. {
  1409.     debug(("Internal_Update "));
  1410.     /* did we have a changed sector at all     */
  1411.     if (unit->mu_TrackChanged != 0) {
  1412.     debug(("needs to write "));
  1413.  
  1414.     if (unit->mu_SectorsPerTrack > unit->mu_CurrentSectors)
  1415.         unit->mu_CurrentSectors = unit->mu_SectorsPerTrack;
  1416.  
  1417.     /*
  1418.      * Only recalculate the CRC on changed sectors. This way, a
  1419.      * sector with a bad CRC won't suddenly be ``repaired''.
  1420.      */
  1421.     {
  1422.         register int i;
  1423.  
  1424.         for (i = unit->mu_CurrentSectors - 1; i >= 0; i--) {
  1425.         if (unit->mu_SectorStatus[i] == CRC_CHANGED) {
  1426.             unit->mu_CrcBuffer[i] = DataCRC(unit->mu_TrackBuffer + i * MS_BPS);
  1427.             debug(("%d: %04x\n", i, unit->mu_CrcBuffer[i]));
  1428.         }
  1429.         }
  1430.     }
  1431.     {
  1432.         DEV        *dev;
  1433.         register struct IOExtTD *tdreq;
  1434.         word        SectorGap;
  1435.  
  1436.         dev = (DEV *) ioreq->iotd_Req.io_Device;
  1437.         tdreq = unit->mu_DiskIOReq;
  1438.         SectorGap = CalculateGapLength(unit->mu_CurrentSectors);
  1439.  
  1440.         ObtainSemaphore(&dev->md_HardwareUse);
  1441.         EncodeTrack(unit->mu_TrackBuffer, dev->md_Rawbuffer,
  1442.             unit->mu_CrcBuffer,
  1443.             unit->mu_CurrentTrack, unit->mu_CurrentSide,
  1444.             SectorGap, unit->mu_CurrentSectors);
  1445.  
  1446.         TDMotorOn(tdreq);
  1447.         if (TDSeek(unit, ioreq, unit->mu_CurrentTrack)) {
  1448.         debug(("Seek error\n"));
  1449.         ioreq->iotd_Req.io_Error = TDERR_SeekError;
  1450.         goto end;
  1451.         }
  1452.         HardwareIO(dev, unit, DSKWRITE);
  1453.  
  1454.         ReleaseSemaphore(&dev->md_HardwareUse);
  1455.         unit->mu_TrackChanged = 0;
  1456.     }
  1457.     }
  1458. end:
  1459.     debug(("done\n"));
  1460. }
  1461.  
  1462. /*
  1463.  * TD_Format writes one or more whole tracks without reading them first.
  1464.  */
  1465.  
  1466. void
  1467. TD_Format(ioreq, unit)
  1468. register struct IOExtTD *ioreq;
  1469. UNIT           *unit;
  1470. {
  1471.     register struct IOExtTD *tdreq = unit->mu_DiskIOReq;
  1472.     DEV        *dev;
  1473.     short        side;
  1474.     int         cylinder;
  1475.     byte       *userbuf;
  1476.     int         length;
  1477.     word        spt;
  1478.     word        gaplen;
  1479.  
  1480.     debug(("CMD_Format "));
  1481.  
  1482.     if (CheckRequest(ioreq, unit))
  1483.     goto termio;
  1484.  
  1485.     userbuf = (byte *) ioreq->iotd_Req.io_Data;
  1486.     length = ioreq->iotd_Req.io_Length / MS_BPS;        /* Sector count */
  1487.     cylinder = ioreq->iotd_Req.io_Offset / MS_BPS;        /* Sector number */
  1488.     /*
  1489.      * Now try to guess the number of sectors the user wants per track.
  1490.      * 40 sectors is the first ambiguous length.
  1491.      */
  1492.     if (length <= MS_SPT_MAX)
  1493.     spt = length;
  1494.     else if (length < 40) {
  1495.     if (length > 0) {
  1496.         for (spt = 8; spt <= MS_SPT_MAX; spt++) {
  1497.         if ((length % spt) == 0)
  1498.             goto found_spt;
  1499.         }
  1500.     }
  1501.     /*
  1502.      * Not 8, 16, 24, 32, 9, 18, 27, 36, 10, 20, or 30? That is an error.
  1503.      */
  1504.     ioreq->iotd_Req.io_Error = IOERR_BADLENGTH;
  1505.     goto termio;
  1506.     } else  /* assume previous number */
  1507.     spt = unit->mu_SectorsPerTrack;
  1508.  
  1509. found_spt:
  1510.     gaplen = CalculateGapLength(spt);
  1511.  
  1512.     /*
  1513.      * Assume the whole disk will have this layout.
  1514.      */
  1515.     unit->mu_SectorsPerTrack = spt;
  1516.  
  1517.     length /= spt;
  1518.     cylinder /= spt;
  1519.  
  1520.     side = cylinder % MS_NSIDES;
  1521.     cylinder /= MS_NSIDES;
  1522.     debug(("userbuf %08lx cylinder %d len %d\n", userbuf, cylinder, length));
  1523.  
  1524.     ioreq->iotd_Req.io_Actual = 0;
  1525.  
  1526.     /*
  1527.      * Write out the current track if we are not going to overwrite it.
  1528.      * After the format operation, the buffer is invalidated.
  1529.      */
  1530.     if (cylinder <= unit->mu_CurrentTrack &&
  1531.     unit->mu_CurrentTrack < cylinder + length)
  1532.     Internal_Update(ioreq, unit);
  1533.  
  1534.     dev = (DEV *) ioreq->iotd_Req.io_Device;
  1535.  
  1536.     while (length > 0) {
  1537.     {
  1538.         register int i;
  1539.  
  1540.         for (i = spt - 1; i >= 0; i--) {
  1541.         unit->mu_CrcBuffer[i] = DataCRC(userbuf + i * MS_BPS);
  1542.         debug(("%d: %04x\n", i, unit->mu_CrcBuffer[i]));
  1543.         }
  1544.     }
  1545.     ObtainSemaphore(&dev->md_HardwareUse);
  1546.     EncodeTrack(userbuf, dev->md_Rawbuffer, unit->mu_CrcBuffer,
  1547.             cylinder, side,
  1548.             gaplen, spt);
  1549.  
  1550.     TDMotorOn(tdreq);
  1551.     if (TDSeek(unit, ioreq, cylinder)) {
  1552.         debug(("Seek error\n"));
  1553.         ioreq->iotd_Req.io_Error = IOERR_BADLENGTH;
  1554.         break;
  1555.     }
  1556.     unit->mu_CurrentSide = side;
  1557.     HardwareIO(dev, unit, DSKWRITE);
  1558.  
  1559.     ReleaseSemaphore(&dev->md_HardwareUse);
  1560.  
  1561.     length--;
  1562.     userbuf += MS_BPS * spt;
  1563.     ioreq->iotd_Req.io_Actual += MS_BPS * spt;
  1564.  
  1565.     if (++side >= MS_NSIDES) {
  1566.         side = 0;
  1567.         if (++cylinder >= unit->mu_NumCyls)
  1568.         goto end;
  1569.     }
  1570.     }
  1571. end:
  1572.     unit->mu_CurrentSide = -1;
  1573.     unit->mu_TrackChanged = 0;
  1574. termio:
  1575.     TermIO(ioreq);
  1576. }
  1577. /* INDENT OFF */
  1578.  
  1579. #asm
  1580.  
  1581. ; we need a buffer for the Sector-ID field to calculate its checksum
  1582. ;SectorHeader:
  1583. ;     dc.b     0           ; track
  1584. ;     dc.b     0           ; side
  1585. ;     dc.b     0           ; sector
  1586. ;     dc.b     2           ; length (2=512 bytes)
  1587. ;     dc.w     0           ; CRC
  1588.  
  1589.     public _EncodeTrack
  1590.  
  1591. ;   EncodeTrack(TrackBuffer, Rawbuffer, Crcs, Track, Side, GapLen, NumSecs)
  1592. ;        4         4        4     2      2       2       2
  1593.  
  1594. _EncodeTrack:
  1595.     movem.l d2-d7/a2-a6,-(sp)  ; save registers
  1596.  
  1597. fp    set    (4*(6+5))+4        ; 4 for return address
  1598. trackbf set    0
  1599. rawbf    set    4
  1600. crcs    set    8
  1601. track    set    12
  1602. side    set    14
  1603. gaplen    set    16
  1604. numsecs set    18
  1605.  
  1606. ; a0    ptr in encoded data (also putmfmbyte)
  1607. ; a2    ptr to mfm encoding table (putmfmbyte)
  1608. ; a3    ptr to data to be crc'd (HeaderCRC)
  1609. ; a4    ptr to table with calculated CRC's
  1610. ; a5    ptr to unencoded data
  1611.  
  1612. ; d0    byte to be encoded (putmfmbyte)
  1613. ; d1    trashed by putmfmbyte
  1614. ; d3    used by putmfmbyte
  1615. ; d5    sector number
  1616. ; d6    general counter of byte spans
  1617. ; d7    sector countdown
  1618.  
  1619.     sub.w    #2,fp+gaplen(sp)   ; gap length between sectors
  1620.     move.l    fp+rawbf(sp),a0    ; pointer to mfmencoded buffer
  1621.     move.l    fp+crcs(sp),a4     ; pointer to precalculated CRCs
  1622.     move.l    fp+trackbf(sp),a5  ; pointer to unencoded data
  1623.     lea    _MfmEncode,a2       ; pointer to MFM lookup table
  1624.  
  1625.     move.w    #$9254,d0       ; a track starts with a gap ($4e)
  1626.     moveq    #INDEXGAP-1,d6
  1627. ingl1    move.w    d0,(a0)+           ; mfmencoded = $9254
  1628.     dbf    d6,ingl1
  1629.  
  1630.     move.w    #$aaaa,d0       ; a track index starts with a gap containing
  1631.     moveq    #INDXGAP-1,d6       ; 12 * 0 (mfm = $aaaa)
  1632. ingl2    move.w    d0,(a0)+
  1633.     dbf    d6,ingl2
  1634.  
  1635.     move.w    #INDEXSYNC,d0       ; The INDEX field begins here, starting
  1636.     move.w    d0,(a0)+           ; with 3 syncs (3 * $c2) with a missing
  1637.     move.w    d0,(a0)+           ; clock bit
  1638.     move.w    d0,(a0)+
  1639.  
  1640.     move.w    #$5552,(a0)+       ; INDEX mark ($fc)
  1641.  
  1642.     move.w    #$9254,d0       ; more gap
  1643.     moveq    #INDEXGAP2-1,d6
  1644. ingl3    move.w    d0,(a0)+           ; mfmencoded = $9254
  1645.     dbf    d6,ingl3
  1646.  
  1647.     lea    -6(sp),sp          ; Reserve room for SectorHeader
  1648. fp    set    fp+6
  1649.     move.w    fp+numsecs(sp),d7  ; number of sectors to encode
  1650.     subq.w    #1,d7           ; minus 1 for dbra
  1651.     moveq    #0,d5           ; start with first sector
  1652.  
  1653. secloop:
  1654.     move.w    #$aaaa,d0       ; a sector starts with a gap containing
  1655.     moveq    #IDGAP2-1,d6       ; 12 * 0 (mfm = $aaaa)
  1656. id2gl    move.w    d0,(a0)+
  1657.     dbf    d6,id2gl
  1658.  
  1659.     move.w    #SYNC,d0       ; The ID field begins here, starting
  1660.     move.w    d0,(a0)+           ; with 3 syncs (3 * $a1) with a missing
  1661.     move.w    d0,(a0)+           ; clock bit
  1662.     move.w    d0,(a0)+
  1663.  
  1664.     move.w    #$5554,(a0)+       ; ID-Address mark ($fe)
  1665.  
  1666.     move.l    sp,a3           ; pointer to Sector-ID buffer
  1667.  
  1668.     moveq    #$5554&1,d3       ; preload d3 for the putmfmbyte routine
  1669.     move.b    fp+track+1(sp),0(a3)  ; insert current track number
  1670.     move.b    fp+side+1(sp),1(a3)   ; side number
  1671.     addq.w    #1,d5           ; sectors start with 1 instead of 0
  1672.     move.b    d5,2(a3)           ; sector number
  1673.     move.b    #MS_BPScode,3(a3)  ; sector length 512 bytes
  1674.     bsr    HeaderCRC       ; calculate checksum
  1675.     move.w    d0,IDDATA(a3)      ; put it past the data
  1676.  
  1677.     moveq    #IDDATA+IDCRC-1,d6 ; 6 bytes Sector-ID
  1678. sidl    move.b    (a3)+,d0           ; get one byte
  1679.     bsr    putmfmbyte       ; encode it
  1680.     dbf    d6,sidl        ; end of buffer ?
  1681.  
  1682.     moveq    #$4e,d0        ; recalculate the MFM value of the
  1683.     bsr    putmfmbyte       ; first gap byte
  1684.  
  1685.     moveq    #DATAGAP1-1-1,d6   ; GAP consisting of
  1686.     move.w    #$9254,d0       ; 22 * $4e
  1687. dg1l    move.w    d0,(a0)+
  1688.     dbf    d6,dg1l
  1689.  
  1690.     moveq    #DATAGAP2-1,d6       ; GAP consisting of
  1691.     move.w    #$aaaa,d0       ; 12 * 0 (mfm = $aaaa)
  1692. dg2l    move.w    d0,(a0)+
  1693.     dbf    d6,dg2l
  1694.  
  1695.     move.w    #SYNC,d0       ; Sector data
  1696.     move.w    d0,(a0)+           ; starts with 3 syncs
  1697.     move.w    d0,(a0)+
  1698.     move.w    d0,(a0)+
  1699.  
  1700.     move.w    #$5545,(a0)+       ; Data Address Mark ($fb)
  1701.  
  1702.     moveq    #$5545&1,d3       ; preload d3
  1703.     move    #MS_BPS-1,d6       ; a sector has 512 bytes
  1704. dblockl move.b    (a5)+,d0           ; get one byte from the buffer
  1705.     bsr    putmfmbyte       ; encode it
  1706.     dbf    d6,dblockl       ; end of sector ?
  1707.  
  1708.     move.b    (a4)+,d0           ; get first byte of CRC
  1709.     bsr    putmfmbyte       ; encode it
  1710.     move.b    (a4)+,d0           ; get second byte
  1711.     bsr    putmfmbyte       ; encode it
  1712.  
  1713.     moveq    #$4e,d0        ; recalculate the MFM value of the
  1714.     bsr    putmfmbyte       ; first gap byte -> -1 in following loop
  1715.  
  1716. ;    moveq    #DATAGAP3-1-1,d6   ; sector ends with a gap
  1717.     move.w    fp+gaplen(sp),d6   ; sector ends with a gap, -1 for dbf
  1718.     move.w    #$9254,d0       ; 80 * $4e
  1719. dg3l    move.w    d0,(a0)+
  1720.     dbf    d6,dg3l
  1721.  
  1722.     dbf    d7,secloop       ; next sector. d5 has been incremented
  1723.  
  1724.     lea    6(sp),sp           ; Free room for SectorHeader
  1725. fp    set    fp-6
  1726.  
  1727.     move.l    fp+rawbf(sp),d6    ; pointer to mfmencoded buffer
  1728.     add.l    #WLEN-2,d6       ; end of encoded buffer (-2 for dbf)
  1729.     move.l    a0,d0           ; (I really want to   sub.l a0,d6 )
  1730.     sub.l    d0,d6           ; length of the remains
  1731.     lsr.l    #1,d6           ; turn into words
  1732.  
  1733.     move.w    #$9254,d0       ; Fill the end of the track with $4e
  1734. endgl    move.w    d0,(a0)+           ; $9254 mfm encoded
  1735.     dbf    d6,endgl
  1736.  
  1737.     movem.l (sp)+,d2-d7/a2-a6
  1738.     rts
  1739.  
  1740. ; putmfmbyte encodes one byte (in D0) into MSDOS MFM format to the location
  1741. ; pointed by A0. D3 has to be preserved between calls !
  1742. ; A2 must contain the pointer to the encoding table.
  1743. ; Destroys D0, D1. Updates A0 and D3. Requires A0, D0, D3.
  1744.  
  1745. putmfmbyte
  1746.     moveq    #16-4,d1
  1747.     lsl.l    d1,d0        ; split the byte into two nibbles
  1748.     lsr.w    d1,d0        ; low nibble is in bits 0..15
  1749.                 ; high nibble in bits 16..31
  1750.     swap    d0        ; process high nibble first
  1751.     and.w    #$0f,d0     ; mask out unwanted bits
  1752.     move.b    0(a2,d0.w),d1   ; get mfmencoded nibble from table
  1753.     btst    #6,d1        ; we now have to work out if
  1754.     bne.s    1$        ; the high bit of the unencoded data
  1755.     btst    #0,d3        ; byte and the low bit of the last
  1756.     bne.s    1$        ; encoded data are both 0. if this is the
  1757.     bset    #7,d1        ; case the first clock bit has to be '1'
  1758. 1$    move.b    d1,(a0)+        ; write high (encoded) nibble
  1759.     swap    d0        ; process low nibble
  1760.     move.b    0(a2,d0.w),d3   ; ....same as above
  1761.     btst    #6,d3
  1762.     bne.s    2$
  1763.     btst    #0,d1
  1764.     bne.s    2$
  1765.     bset    #7,d3
  1766. 2$    move.b    d3,(a0)+
  1767.     rts
  1768.  
  1769. #endasm
  1770. #endif                /* READONLY */
  1771. #asm
  1772.  
  1773. ; The CRC is computed not only over the actual data, but including
  1774. ; the SYNC mark (3 * $a1) and the 'ID/DATA - Address Mark' ($fe/$fb).
  1775. ; As we don't read or encode these fields into our buffers, we have to
  1776. ; preload the registers containing the CRC with the values they would have
  1777. ; after stepping over these fields.
  1778. ;
  1779. ; How CRCs "really" work:
  1780. ;
  1781. ; First, you should regard a bitstring as a series of coefficients of
  1782. ; polymomials. We calculate with these polynomials in modulo-2
  1783. ; arithmetic, in which both add and subtract are done the same as
  1784. ; exclusive-or. Now, we modify our data (a very long polynomial) in
  1785. ; such a way that it becomes divisible by the CCITT-standard 16-bit
  1786. ;         16   12   5
  1787. ; polynomial:    x  + x    + x + 1, represented by $11021. The easiest
  1788. ; way to do this would be to multiply (using proper arithmetic) our
  1789. ; datablock with $11021. So we have:
  1790. ;   data * $11021         =
  1791. ;   data * ($10000 + $1021)      =
  1792. ;   data * $10000 + data * $1021
  1793. ; The left part of this is simple: Just add two 0 bytes. But then
  1794. ; the right part (data $1021) remains difficult and even could have
  1795. ; a carry into the left part. The solution is to use a modified
  1796. ; multiplication, which has a result that is not correct, but with
  1797. ; a difference of any multiple of $11021. We then only need to keep
  1798. ; the 16 least significant bits of the result.
  1799. ;
  1800. ; The following algorithm does this for us:
  1801. ;
  1802. ;   unsigned char *data, c, crclo, crchi;
  1803. ;   while (not done) {
  1804. ;    c = *data++ + crchi;
  1805. ;    crchi = (@ c) >> 8 + crclo;
  1806. ;    crclo = @ c;
  1807. ;   }
  1808. ;
  1809. ; Remember, + is done with EOR, the @ operator is in two tables (high
  1810. ; and low byte separately), which is calculated as
  1811. ;
  1812. ;      $1021 * (c & $F0)
  1813. ;  xor $1021 * (c & $0F)
  1814. ;  xor $1021 * (c >> 4)         (* is regular multiplication)
  1815. ;
  1816. ;
  1817. ; Anyway, the end result is the same as the remainder of the division of
  1818. ; the data by $11021. I am afraid I need to study theory a bit more...
  1819.  
  1820.  
  1821. ; This is the entry to calculate the checksum for the sector-id field
  1822. ; requires:  a3 = pointer to the unencoded data
  1823. ; returns:   d0 = CRC
  1824.  
  1825. HeaderCRC:
  1826.     movem.l  d1-d3/a3-a5,-(sp) ; save registers
  1827.     move.w     #$b2,d0       ; preload registers
  1828.     moveq     #$30,d1       ; (CRC for $a1,$a1,$a1,$fb)
  1829.     moveq     #3,d3           ; calculate checksum for 4 bytes
  1830.     bra.s     getCRC        ; (=track,side,sector,sectorlength)
  1831.  
  1832. ; This is the entry to calculate the checksum for the data field
  1833. ; requires:  a3 = pointer to the unencoded data
  1834. ; returns:   d0 = CRC
  1835.  
  1836. ; C entry point for DataCRC(byte *data)
  1837.  
  1838. _DataCRC:
  1839.     movem.l d1-d3/a3-a5,-(sp)  ; save registers
  1840. fp    set    (4*(3+3))+4
  1841. data    set    0
  1842.     move.l    fp+data(sp),a3     ; get parameter
  1843.     move.w     #$e2,d0       ; preload the CRC registers
  1844.     move.w     #$95,d1       ; (CRC for $a1,$a1,$a1,$fe)
  1845.     move.w     #MS_BPS-1,d3       ; a sector 512 bytes
  1846.  
  1847. getCRC    lea     CRCTable1,a4
  1848.     lea     CRCTable2,a5
  1849.     moveq     #0,d2
  1850.  
  1851. 1$    move.b     (a3)+,d2
  1852.     eor.b     d0,d2
  1853.     move.b     0(a4,d2.w),d0
  1854.     eor.b     d1,d0
  1855.     move.b     0(a5,d2.w),d1
  1856.     dbf     d3,1$
  1857.  
  1858.     lsl.w     #8,d0
  1859.     move.b     d1,d0
  1860.     movem.l  (sp)+,d1-d3/a3-a5
  1861.     rts
  1862.  
  1863.  
  1864. CRCTable1:
  1865.     dc.b $00,$10,$20,$30,$40,$50,$60,$70,$81,$91,$a1,$b1,$c1,$d1,$e1,$f1
  1866.     dc.b $12,$02,$32,$22,$52,$42,$72,$62,$93,$83,$b3,$a3,$d3,$c3,$f3,$e3
  1867.     dc.b $24,$34,$04,$14,$64,$74,$44,$54,$a5,$b5,$85,$95,$e5,$f5,$c5,$d5
  1868.     dc.b $36,$26,$16,$06,$76,$66,$56,$46,$b7,$a7,$97,$87,$f7,$e7,$d7,$c7
  1869.     dc.b $48,$58,$68,$78,$08,$18,$28,$38,$c9,$d9,$e9,$f9,$89,$99,$a9,$b9
  1870.     dc.b $5a,$4a,$7a,$6a,$1a,$0a,$3a,$2a,$db,$cb,$fb,$eb,$9b,$8b,$bb,$ab
  1871.     dc.b $6c,$7c,$4c,$5c,$2c,$3c,$0c,$1c,$ed,$fd,$cd,$dd,$ad,$bd,$8d,$9d
  1872.     dc.b $7e,$6e,$5e,$4e,$3e,$2e,$1e,$0e,$ff,$ef,$df,$cf,$bf,$af,$9f,$8f
  1873.     dc.b $91,$81,$b1,$a1,$d1,$c1,$f1,$e1,$10,$00,$30,$20,$50,$40,$70,$60
  1874.     dc.b $83,$93,$a3,$b3,$c3,$d3,$e3,$f3,$02,$12,$22,$32,$42,$52,$62,$72
  1875.     dc.b $b5,$a5,$95,$85,$f5,$e5,$d5,$c5,$34,$24,$14,$04,$74,$64,$54,$44
  1876.     dc.b $a7,$b7,$87,$97,$e7,$f7,$c7,$d7,$26,$36,$06,$16,$66,$76,$46,$56
  1877.     dc.b $d9,$c9,$f9,$e9,$99,$89,$b9,$a9,$58,$48,$78,$68,$18,$08,$38,$28
  1878.     dc.b $cb,$db,$eb,$fb,$8b,$9b,$ab,$bb,$4a,$5a,$6a,$7a,$0a,$1a,$2a,$3a
  1879.     dc.b $fd,$ed,$dd,$cd,$bd,$ad,$9d,$8d,$7c,$6c,$5c,$4c,$3c,$2c,$1c,$0c
  1880.     dc.b $ef,$ff,$cf,$df,$af,$bf,$8f,$9f,$6e,$7e,$4e,$5e,$2e,$3e,$0e,$1e
  1881.  
  1882. CRCTable2:
  1883.     dc.b $00,$21,$42,$63,$84,$a5,$c6,$e7,$08,$29,$4a,$6b,$8c,$ad,$ce,$ef
  1884.     dc.b $31,$10,$73,$52,$b5,$94,$f7,$d6,$39,$18,$7b,$5a,$bd,$9c,$ff,$de
  1885.     dc.b $62,$43,$20,$01,$e6,$c7,$a4,$85,$6a,$4b,$28,$09,$ee,$cf,$ac,$8d
  1886.     dc.b $53,$72,$11,$30,$d7,$f6,$95,$b4,$5b,$7a,$19,$38,$df,$fe,$9d,$bc
  1887.     dc.b $c4,$e5,$86,$a7,$40,$61,$02,$23,$cc,$ed,$8e,$af,$48,$69,$0a,$2b
  1888.     dc.b $f5,$d4,$b7,$96,$71,$50,$33,$12,$fd,$dc,$bf,$9e,$79,$58,$3b,$1a
  1889.     dc.b $a6,$87,$e4,$c5,$22,$03,$60,$41,$ae,$8f,$ec,$cd,$2a,$0b,$68,$49
  1890.     dc.b $97,$b6,$d5,$f4,$13,$32,$51,$70,$9f,$be,$dd,$fc,$1b,$3a,$59,$78
  1891.     dc.b $88,$a9,$ca,$eb,$0c,$2d,$4e,$6f,$80,$a1,$c2,$e3,$04,$25,$46,$67
  1892.     dc.b $b9,$98,$fb,$da,$3d,$1c,$7f,$5e,$b1,$90,$f3,$d2,$35,$14,$77,$56
  1893.     dc.b $ea,$cb,$a8,$89,$6e,$4f,$2c,$0d,$e2,$c3,$a0,$81,$66,$47,$24,$05
  1894.     dc.b $db,$fa,$99,$b8,$5f,$7e,$1d,$3c,$d3,$f2,$91,$b0,$57,$76,$15,$34
  1895.     dc.b $4c,$6d,$0e,$2f,$c8,$e9,$8a,$ab,$44,$65,$06,$27,$c0,$e1,$82,$a3
  1896.     dc.b $7d,$5c,$3f,$1e,$f9,$d8,$bb,$9a,$75,$54,$37,$16,$f1,$d0,$b3,$92
  1897.     dc.b $2e,$0f,$6c,$4d,$aa,$8b,$e8,$c9,$26,$07,$64,$45,$a2,$83,$e0,$c1
  1898.     dc.b $1f,$3e,$5d,$7c,$9b,$ba,$d9,$f8,$17,$36,$55,$74,$93,$b2,$d1,$f0
  1899.  
  1900. #endasm
  1901.  
  1902. /* INDENT ON */
  1903.